<template>
	<view class="container" @tap="togglePicker(0)">
		<!--内容-->
		<view class="scroll" :style="{height: scrollHeight}">
			<scroll-view :scroll-into-view="scrollViewId" scroll-y style="height: 100%;">
				<view class="item-space"></view>
				<!-- <view class="time">晚上 10:04</view> -->
				<view v-for="(item, index) in list" :key="index">
					<!--撤销-->
					<view v-if="item.msgType == 'cancel'" class="cancel">
						<text v-if="item.source == fromUserId" class="text">你撤回了一条消息</text>
						<text v-else class="text">成员 {{ item.source }} 撤回了一条消息</text>
					</view>
					<view v-else class="item flex-row" :class="[item.source == fromUserId ? 'right' : 'left']">
						<!--处理头像-->
						<view v-if="item.source == fromUserId">
							<image v-if="fromUserFace" :src="fromUserFace" class="face"></image>
							<image v-else src="@/static/img/face.png" class="face"></image>
						</view>
						<view v-else>
							<image v-if="item.toUserFace || item.userFace" :src="item.toUserFace || item.userFace"
								class="face"></image>
							<image v-else src="@/static/ai-tx.png" class="face"></image>
						</view>
						<!--文本-->
						<view v-if="item.msgType == 'text'" class="content flex-row">
							{{ item.content }}
						</view>
						<!--图片-->
						<image v-if="item.msgType == 'image'" @longpress="longPress(item)" :src="item.content"
							mode="widthFix" style="width: 320upx;"></image>
						<!-- 等待服务器回应时的效果 -->
						<view v-if="item.msgType == 'loading'" class="loading">
							<image :src="item.content" mode="widthFix" style="width: 80upx;"></image>
						</view>

						<!--地图-->
						<!-- <view v-if="item.msgType == 'map'" class="content map" @tap="openLocation(item.content)">
							<view class="title">{{ item.content.address }}</view>
							<map class="box" :latitude="item.content.latitude" :longitude="item.content.longitude"
								:markers="[{latitude: item.content.latitude, longitude: item.content.longitude, iconPath: '@/static/img/marker.png'}]"
								@tap="openLocation(item.content)"></map>
						</view> -->
						<!--语音-->
						<view v-if="item.msgType == 'voice'" @tap="playVoice(item)" class="content">
							<image v-show="voicePlayingId != item.id" src="@/static/img/audio.png" class="voice-icon">
							</image>
							<image v-show="voicePlayingId == item.id" src="@/static/img/audio-play.gif"
								class="voice-icon"></image>
							<view class="voice-content" @longpress="longPress(item.text,index)">
								{{item.text}}
							</view>
							<!-- 翻译结果 -->
							<view class="translation-result" v-if='item.translationText != "" && item.source == 1'>
								{{item.translationText}}
							</view>
							<view class="tips" v-if='item.source == 1'>
								长按翻译
							</view>
						</view>
					</view>
				</view>
				<view id="bottom"></view>
			</scroll-view>
		</view>
		<!--输入-->
		<view class="oper flex-row" @tap.prevent.stop="">
			<!--语音切换-->
			<!-- <image v-if="isEdit" @tap="toggleEdit(false)" src="@/static/img/voice-circle.png" class="icon"></image>
			<image v-else @tap="toggleEdit(true)" src="@/static/img/keyboard.png" class="icon"></image> -->
			<!--语音切换-->
			<input v-if="isEdit" @focus="inputFocus" :focus="isFocus" :cursor-spacing="8" :adjust-position="false"
				type="text" v-model="content" class="input" placeholder="请输入内容" />
			<!-- <u--input confirmType='发送' v-if="isEdit" placeholder="请输入内容" border="surround" v-model="content"></u--input> -->
			<!-- <view v-else @touchstart="startVoice" @touchend="endVoice" class="input" style="text-align: center;">按住开吼
			</view> -->
			<!-- <button class="u-reset-button voice-btn" @touchstart="touchStart"
				@touchend="touchEnd">{{voiceState}}</button> -->
			<!-- 切换 -->
			<!-- <image @tap="onReset" src="@/static/refresh.png" class="icon"></image> -->
			<!-- 清空聊天记录 -->
			<image @tap="onDeleteMsgList" src="@/static/delete.png" class="icon"></image>
			<!--表情-->
			<!-- <image @tap="togglePicker(200, 'emoji')" src="@/static/img/emoji.png" class="icon"></image> -->
			<!--发送-->
			<view @touchend.prevent="send" class="btn">发送</view>
			<!--附件-->
			<!-- <image @tap="togglePicker(86, 'file')" v-show="!content" src="@/static/img/add.png" class="icon"></image> -->
		</view>
		<!--表情-->
		<!-- <view v-show="showEmoji" class="emoji" @tap.prevent.stop="">
			<view class="list">
				<view class="item" @tap="content += item" v-for="(item, index) in emojis" :key="index">{{ item }}</view>
			</view>
		</view> -->

		<!--附件-->
		<!-- <view v-show="showFile" class="file" @tap.prevent.stop="">
			<view class="list flex-row">
				<view class="item flex-column" @tap="uploadImage(['album'])">
					<image src="@/static/img/album.png" mode="widthFix" class="icon"></image>
					<view class="text">相册</view>
				</view>
				<view class="item flex-column" @tap="uploadImage(['camera'])">
					<image src="@/static/img/photo.png" mode="widthFix" class="icon"></image>
					<view class="text">拍照</view>
				</view>
				<view class="item flex-column" @tap="getLocation">
					<image src="@/static/img/location.png" mode="widthFix" class="icon"></image>
					<view class="text">位置</view>
				</view>
			</view>
		</view> -->
		<!--语音-->
		<!-- 是否清空记录提示 -->

		<my-voice v-show="showVoice"></my-voice>
		<!-- 翻译选项 -->
		<u-action-sheet :actions="actions" :show="showActions" @select='selectActions'> </u-action-sheet>

	</view>
</template>

<script>
	import emoji from '@/plugins/emoji.js'
	import myVoice from '@/components/self-voice/index.vue'
	import {
		sendMessage,
		sendEdits
	} from "@/apis/modules/index.js"
	import CryptoJS from 'crypto-js';
	const innerAudioContext = uni.createInnerAudioContext()
	const recorderManager = uni.getRecorderManager()
	let plugin = requirePlugin("WechatSI");
	let manager = plugin.getRecordRecognitionManager();
	import {
		xunfeiSocketTask,
		linkXunfeiSocket
	} from "@/common/audio.js"
	const APPID = '153511e4'
	const API_SECRET = 'NjI2NDgxOGQzMzYwMGY5OTgxMWI2OGQ2'
	const API_KEY = 'e9be89532ac0b69d59752a5317b60341'
	export default {
		components: {
			myVoice
		},
		data() {
			return {
				emojis: [],
				isEdit: true,
				isFocus: false,
				showEmoji: false,
				showFile: false,
				showVoice: false,
				scrollHeight: 'auto', // 内容区域高度
				statusBarHeight: 0, // 状态栏高度
				scrollViewId: '', // 滚动到最底部
				voicePlayingId: '', // 正在播放的消息ID
				voiceState: '按住说话',
				content: '',
				list: [],
				socketOpen: false,
				socketMsgQueue: [],
				fromUserId: '2',
				fromUserFace: uni.getStorageSync('userFace'),
				toUserId: '',
				toUserName: '',
				actions: [{
						name: '翻译',
						subname: "翻译成中文",
						color: '#ffaa7f',
						value: 1
					},
					{
						name: '取消',
						value: 0
					}
				],
				showActions: false,
				translateData: null,
				showModal: true,
				toAudioText: '你是？',
				xunfeiSocketTask: '',
				audioBase64:''
			}
		},
		onLoad(option) {
			// this.webSocketSend()
			this.linkXunfeiSocket()
			if (option.text != '') {
				this.list.push({
					source: 1,
					target: 1,
					content: require('@/static/loading.gif'),
					userFace: '',
					type: 'single',
					msgType: 'loading'
				})
				this.onSendMessage(option.text)
			}
			// 初始化内容高度
			this.setScrollHeight()
			// 初始化状态栏高度
			uni.getSystemInfo({
				success: res => {
					this.statusBarHeight = res.statusBarHeight
				}
			})
			// 结束录音
			// recorderManager.onStop(res => {
			// 	this.upload(res.tempFilePath)
			// })
			// 结束播放
			innerAudioContext.onEnded(res => {
				this.voicePlayingId = ''
			})
			// 设置标题
			uni.setNavigationBarTitle({
				title: option.toUserName
			})
			// 获取参数
			this.toUserId = option.toUserId
			this.toUserName = option.toUserName
		},
		onHide() {
			innerAudioContext.stop()
		},
		onBackPress() {
			if (this.showFile || this.showEmoji) {
				this.showFile = false
				this.showEmoji = false
				this.setScrollHeight(0)
				return true
			}
			return false
		},
		methods: {
			async getWebsocketUrl() {

				// 合成讯飞语音请求地址
				const that = this;
				return await new Promise((resolve, reject) => {
					var apiKey = API_KEY; // 讯飞控制台查看
					var apiSecret = API_SECRET; // 讯飞控制台查看
					var url = 'wss://tts-api.xfyun.cn/v2/tts';
					var host = 'http://192.168.31.171:8081'; // 请求的主机地址
					var date = new Date().toGMTString();
					var algorithm = 'hmac-sha256';
					var headers = 'host date request-line';
					var signatureOrigin = `host: ${host}\ndate: ${date}\nGET /v2/tts HTTP/1.1`;
					var signatureSha = CryptoJS.HmacSHA256(signatureOrigin, apiSecret);
					var signature = CryptoJS.enc.Base64.stringify(signatureSha);
					var authorizationOrigin =
						`api_key="${apiKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`;
					var authorization = that.base64_encode(authorizationOrigin);
					url = `${url}?authorization=${authorization}&date=${date}&host=${host}`;
					resolve(url);
				});
			},
			async linkXunfeiSocket() {
				// 连接讯飞Socket服务器
				let url = await this.getWebsocketUrl();
				let XunfeiSocketTask;
				await new Promise((resolve, reject) => {
					XunfeiSocketTask = uni.connectSocket({
						url: encodeURI(url),
						header: {
							'content-type': 'application/json'
						},
						success: () => {
							console.log(`讯飞 connect成功`);
							resolve();
						},
						fail: () => {
							console.log('讯飞 connect失败');
							reject();
						}
					});
				});
				this.xunfeiSocketTask = XunfeiSocketTask;
				this.initXunFei(this.xunfeiSocketTask);
			},
			initXunFei(xunfeiSocketTask) {
				// 监听消息
				xunfeiSocketTask.onMessage(res => {
					// console.log('接收讯飞消息');
					console.log("res.data接收讯飞消息: ", res.data);
					this.result(res.data);
				});
				xunfeiSocketTask.onOpen(() => {
					// console.log('讯飞websocket打开');
					this.webSocketSend();
				});
				xunfeiSocketTask.onClose(res => {
					clearTimeout(this.playTimeout);
					// console.error('讯飞断开');
				});
				xunfeiSocketTask.onError(err => {
					// console.error('讯飞连接错误', err);
				});
			},
			base64_encode(str) {
				// 编码，配合encodeURIComponent使用
				var c1, c2, c3;
				var base64EncodeChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
				var i = 0,
					len = str.length,
					strin = '';
				while (i < len) {
					c1 = str.charCodeAt(i++) & 0xff;
					if (i == len) {
						strin += base64EncodeChars.charAt(c1 >> 2);
						strin += base64EncodeChars.charAt((c1 & 0x3) << 4);
						strin += '==';
						break;
					}
					c2 = str.charCodeAt(i++);
					if (i == len) {
						strin += base64EncodeChars.charAt(c1 >> 2);
						strin += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xf0) >> 4));
						strin += base64EncodeChars.charAt((c2 & 0xf) << 2);
						strin += '=';
						break;
					}
					c3 = str.charCodeAt(i++);
					strin += base64EncodeChars.charAt(c1 >> 2);
					strin += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xf0) >> 4));
					strin += base64EncodeChars.charAt(((c2 & 0xf) << 2) | ((c3 & 0xc0) >> 6));
					strin += base64EncodeChars.charAt(c3 & 0x3f);
				}
				return strin;
			},
			webSocketSend() {
				let params = {
					common: {
						app_id: APPID // 讯飞控制台查看
					},
					business: {
						aue: 'lame', // 音频编码表示mp3格式，当aue=lame时需传参sfl=1
						sfl: 1,
						vcn: 'xiaoyan', // 发音人选择
						tte: 'UTF8'
					},
					data: {
						status: 2,
						text: CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(this.toAudioText))
					}
				};

				this.xunfeiSocketTask.send({
					data: JSON.stringify(params),
					success: res => {
						// console.log('发出讯飞消息');
					},
					fail: err => {
						// console.log('发出讯飞消息失败', err);
					}
				});
			},
			result(resultData) {
				let jsonData = JSON.parse(resultData);
				//陆续合并接收的base64音频流 
				this.audioBase64 += jsonData.data.audio;
				if (jsonData.code !== 0) {
					// 合成失败
					console.log(`${jsonData.code}:${jsonData.message}`);
					return;
				}
				if (jsonData.code === 0 && jsonData.data.status === 2) {
					// 分段发送完成，转成语音文件关闭连接
					// 注意：将base64转化成ArrayBuffer
					const data = uni.base64ToArrayBuffer(this.audioBase64);
					const target = `${wx.env.USER_DATA_PATH}/${new Date().getTime()}.mp3`;
					console.log("target, data,: ",target, data,);
					try {
						// 使用fs.writeFileSync完成音频文件的转化
						this.list.push({
							id: this.algorithm(),
							source: this.fromUserId,
							target: this.toUserId,
							content: target,
							text: '',
							userFace: '',
							type: 'single',
							msgType: 'voice'
						})
						const res = fs.writeFileSync(target, data, 'binary');
						this.playAudio.push(target);
						this.xunfeiSocketTask.close();
						this.audioBase64 = '';
					} catch (e) {
						console.error(e);
					}
				}
			},
			// 语音输入
			onVoiceInput(tempFilePath, content) {
				this.list.push({
					id: this.algorithm(),
					source: this.fromUserId,
					target: this.toUserId,
					content: tempFilePath,
					text: content,
					userFace: '',
					type: 'single',
					msgType: 'voice'
				})
				this.scrollViewId = 'bottom'

				this.list.push({
					source: 1,
					target: 1,
					content: require('@/static/loading.gif'),
					userFace: '',
					type: 'single',
					msgType: 'loading'
				})
				this.onSendMessage(content)
			},

			// 初始化滚动
			initScrollBar() {
				setTimeout(() => {
					this.scrollViewId = ''
					setTimeout(() => {
						this.scrollViewId = 'bottom'
						setTimeout(() => {
							this.scrollViewId = ''
						}, 100)
					}, 100)
				}, 100)
			},
			// 监听输入聚焦
			inputFocus(e) {
				console.log('e', e);
				this.setScrollHeight(e.detail.height)
				this.initScrollBar()
				uni.onKeyboardHeightChange(res => {
					this.setScrollHeight(res.height)
					this.initScrollBar()
				})
			},
			// 设置scroll的高度
			setScrollHeight(descHeight = 0) {
				// #ifdef MP-WEIXIN
				this.scrollHeight = `calc(100vh - 110rpx - ${descHeight}px)`
				// #endif
				// #ifdef APP-PLUS
				this.scrollHeight = `calc(100vh - 110upx - ${descHeight}px)`
				// #endif
				// #ifdef H5
				this.scrollHeight = `calc(100vh - 110upx - 88rpx - ${descHeight}px)`
				// #endif
			},
			// 切换选择
			togglePicker(height = 0, type = '') {
				this.showEmoji = false
				this.showFile = false
				let status = height > 0 ? true : false
				switch (type) {
					case 'emoji':
						this.showEmoji = status;
						break
					case 'file':
						this.showFile = status;
						break
				}
				setTimeout(() => {
					this.setScrollHeight(height)
					this.initScrollBar()
				}, 50)
			},
			// 切换语音与编辑
			toggleEdit(bool) {
				this.isEdit = bool
				this.isFocus = bool
				this.setScrollHeight(0)
			},
			// 开始录音
			startVoice() {
				this.showVoice = true
				recorderManager.start()
			},
			// 结束录音
			endVoice() {
				this.showVoice = false
				recorderManager.stop()
			},
			// 上传
			upload(filePath) {
				this.$util.loading('上传中')
				uni.uploadFile({
					url: this.$api.upload,
					name: 'file',
					filePath,
					formData: {
						userId: this.fromUserId
					},
					header: this.$util.getHeader(),
					success: res => {
						uni.hideLoading()
						let data = JSON.parse(res.data)
						this.pushMessage(data.data, 'voice')
					},
					fail: err => {
						uni.hideLoading()
					}
				})
			},
			// 播放录音
			playVoice(item) {
				if (this.voicePlayingId) {
					this.voicePlayingId = ''
					// 结束播放
					innerAudioContext.stop()
				} else {
					this.voicePlayingId = item.id
					innerAudioContext.src = item.content
					// 播放
					innerAudioContext.play()
				}
			},
			// 长按
			longPress(msg, index) {
				this.translateData = {
					content: msg,
					index: index
				}
				this.showActions = true
			},

			// 发送消息
			async send() {
				if (this.content == '') return uni.showToast({
					title: '请输入文本内容',
					icon: 'none'
				})
				this.list.push({
					source: this.fromUserId,
					target: this.toUserId,
					content: this.content,
					userFace: '',
					type: 'single',
					msgType: 'text'
				})
				// 初始化滚动条
				// this.initScrollBar()
				this.scrollViewId = 'bottom'
				this.list.push({
					source: 1,
					target: 1,
					content: require('@/static/loading.gif'),
					userFace: '',
					type: 'single',
					msgType: 'loading'
				})

				this.onSendMessage(this.content)
				this.content = ''
			},
			// 向服务端发送消息
			async onSendMessage(content) {
				let res = await sendMessage({
					msg: content
				})

				console.log('res', res);
				// 服务端响应时删除loading状态
				let Index = this.list.findIndex(item => item.msgType === 'loading')
				this.list.splice(Index, 1)
				this.list.push({
					id: this.algorithm(),
					source: res.source,
					target: res.toUserId,
					content: res.msg.content,
					text: content,
					userFace: '',
					type: 'single',
					msgType: 'text'
				})
				// this.onTextToSpeech(res, res.msg.content)
				// 初始化滚动条
				this.initScrollBar()
			},
			// 生成ID
			algorithm() {
				let abc = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'g', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
					't', 'u', 'v', 'w', 'x', 'y', 'z'
				];
				let [max, min] = [Math.floor(Math.random() * (10 - 7 + 1) + 1), Math.floor(Math.random() * (17 - 10 + 1) +
					17)];
				abc = abc.sort(() => 0.4 - Math.random()).slice(max, min).slice(0, 8).join("");
				var a = new Date().getTime() + abc;
				return a
			},
			// 清空聊天记录
			onDeleteMsgList() {
				let that = this
				uni.showModal({
					title: '提示',
					content: '清空消息记录?',
					cancelText: "取消", // 取消按钮的文字  
					confirmText: "确认", // 确认按钮的文字  
					showCancel: true, // 是否显示取消按钮，默认为 true
					success: (res) => {
						if (res.confirm) {
							that.list = []
							console.log('comfirm') //点击确定之后执行的代码
						} else {
							console.log('cancel') //点击取消之后执行的代码
						}
					}
				})
			},
			// 确认清除
			onConfirmMsgList() {
				this.showModal = false
			},
			// 重置
			async onReset() {
				let res = await sendEdits()
				console.log("重置res: ", res);
			}
		}
	}
</script>

<style lang="scss" scoped>
	page {
		background-color: #000;
	}

	.container {
		height: 100vh;
		overflow: hidden;
	}

	/* #ifdef H5 */
	.container {
		height: calc(100vh - 88upx);
	}

	/* #endif */

	.status_bar,
	.container,
	.header,
	.emoji,
	.file {
		background-color: #F3F3F3;
	}

	.header {
		border-bottom: 2upx solid #EEE;

		.center {
			font-weight: bold;
		}
	}

	.map {
		width: 60%;
		height: 300upx;
		background-color: #FFF !important;

		&::before {
			border-right: 30upx solid #FFF !important;
		}

		.title {
			height: 80upx;
			font-size: 28upx;
			overflow: hidden;
			text-overflow: ellipsis;
			display: -webkit-box;
			-webkit-line-clamp: 2;
			-webkit-box-orient: vertical;
		}

		.box {
			width: 100%;
			height: 170upx;
			margin-top: 10upx;
		}
	}

	.emoji {
		height: 400upx;
		padding: 0 0 20upx 20upx;
		position: relative;

		.list {
			width: 100%;
			height: 400upx;
			padding: 20upx 0;
			overflow-y: auto;

			.item {
				float: left;
				display: block;
				height: 60upx;
				line-height: 60upx;
				width: calc(100% / 12);
				margin-right: 20upx;
			}
		}
	}

	.file {
		padding: 30upx 20upx;

		.list {
			overflow: hidden;
			padding-left: 10upx;
			justify-content: flex-start;
		}

		.item {
			float: left;
			width: 110upx;
			height: 110upx;
			border-radius: 10upx;
			margin-right: 40upx;
			background-color: #FFF;

			.icon {
				width: 50upx;
			}

			.text {
				font-size: 24upx;
				margin-top: 4upx;
			}
		}
	}

	.oper {
		height: 110upx;
		padding: 0 20upx;
		box-sizing: border-box;
		border-top: 2upx solid #EEE;
		border-bottom: 2upx solid #EEE;
		padding-bottom: constant(safe-area-inset-bottom);
		padding-bottom: env(safe-area-inset-bottom);

		.input {
			height: 68upx;
			line-height: 68upx;
			padding: 0 20upx;
			font-size: 28upx;
			border-radius: 10upx;
			background-color: #fff;
			width: calc(100% - 120upx - 20upx - 40upx - 60upx);
		}

		.voice-btn {
			flex: 1;
			height: 100rpx;
			border: 4rpx solid #ccc;
			line-height: 100rpx;
		}

		.icon {
			width: 60upx;
			height: 60upx;
			margin: 0 10rpx;
		}

		.btn {
			color: #fff;
			width: 90upx;
			height: 52upx;
			font-size: 24upx;
			line-height: 52upx;
			text-align: center;
			border-radius: 10upx;
			background-color: #2BA245;
		}
	}

	.scroll {
		overflow-y: auto;
		transition: all 0.1s ease;
		height: calc(100vh - 88upx - 110upx - var(--status-bar-height));

		/* #ifdef MP-WEIXIN */
		height: calc(100vh - 88upx - var(--status-bar-height));
		/* #endif */
		/* #ifdef H5 */
		height: calc(100vh - 88upx - 110upx - var(--status-bar-height));
		/* #endif */

		.item-space {
			height: 30upx;
		}

		.time {
			color: #666;
			font-size: 24upx;
			text-align: center;
			margin-bottom: 20upx;

		}

		.cancel {
			width: 100%;
			height: 40upx;
			text-align: center;
			margin-bottom: 30upx;

			.text {
				color: #999;
				font-size: 24upx;
			}
		}

		.item {
			margin: 0 30upx 30upx;
			align-items: flex-start;
			justify-content: flex-start;

			.loading {
				border-radius: 14rpx;

				image {
					border-radius: 14rpx;
				}
			}

			.face {
				width: 80upx;
				height: 80upx;
				border-radius: 10upx;
			}

			.voice-content {}

			.translation-result {
				border-top: 2rpx solid #ccc;
				margin: 10rpx 0;
				font-size: 26rpx;
				color: #000;
			}

			.tips {
				margin-top: 20rpx;
				color: #ccc;
				font-size: 22rpx;
			}

			.content {
				color: #000;
				font-size: 32upx;
				min-height: 80upx;
				border-radius: 10upx;
				padding: 20upx 24upx;
				background-color: #fff;
				word-break: break-all;
				word-wrap: break-word;
				max-width: calc(100% - 100upx - 120upx);
				position: relative;

				&::before {
					content: '';
					width: 0;
					height: 0;
					border-right: 30upx solid #FFF;
					border-top: 20upx solid transparent;
					border-bottom: 20upx solid transparent;
					position: absolute;
					top: 24upx;
				}

				.voice-icon {
					width: 32upx;
					height: 40upx;
					margin-right: 180upx;
					margin-bottom: -8upx;
				}
			}

			&.left {
				.face {
					margin-right: 30upx;
				}

				.content::before {
					left: -20upx;
				}
			}

			&.right {
				flex-direction: row-reverse;

				.face {
					margin-left: 30upx;
				}

				.content {
					background-color: #A0EA6F;

					&::before {
						right: -20upx;
						transform: rotate(180deg);
						border-right: 30upx solid #A0EA6F;
					}

					.voice-icon {
						margin-right: 0;
						margin-left: 180upx;
						transform: rotate(180deg);
					}
				}
			}
		}

		#bottom {
			height: 0;
		}
	}
</style>